﻿using Common.Helpers;
using Common.Interfaces;
using Common.Services;
using Common.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc.Controllers;
using System.Reflection;
using System.ComponentModel;
using System.Text.RegularExpressions;
using Common.Caching;
using System.Text;

namespace Common.Middlewares;

internal class LoggingMiddleware : IMiddleware, IScopedDependency
{
    private readonly ILogger<LoggingMiddleware> _logger;
    private readonly Stopwatch _timer;
    private readonly ISnowFlakeService _snowFlakeService;
    private readonly UserAgentParser _userAgentParser;
    private readonly IDateTime _dateTime;
    private readonly ICurrentUserService _currentUserService;
    public LoggingMiddleware(
        ILogger<LoggingMiddleware> logger,
        ISnowFlakeService snowFlakeService,
        UserAgentParser userAgentParser,
        IDateTime dateTime,
        ICurrentUserService currentUserService)
    {
        _logger = logger;
        _timer = new Stopwatch();
        _snowFlakeService = snowFlakeService;
        _userAgentParser = userAgentParser;
        _dateTime = dateTime;
        _currentUserService = currentUserService;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var id = _snowFlakeService.GenerateId();
        string controllerDescription=string.Empty;
        string actionDescription=string.Empty;
        var requestAPI = context.Request.Path;
        var requestMethod = context.Request.Method;
        var ip = context.Connection.RemoteIpAddress?.ToString();
        long elapsedMilliseconds = 0;
        var requestTime = _dateTime.Now;
        var traceId = "";
        var requestHeader = context.Request.Headers.ToJson();
        var responseHeader = string.Empty;
        var responseBody = string.Empty;
        var userAgent = context.Request.Headers["User-Agent"][0];
        var userAgentInfo = await _userAgentParser.ParseUserAgentAsync(userAgent, ip);
        var userAgentInfos = userAgentInfo.Split("-");
        string? os = userAgentInfos[0];
        string? browser = userAgentInfos[1];
        string? location = userAgentInfos[2];
        string? behavior = "操作日志";

        // 复制原始请求体以备后续使用
        var requestBodyStream = new MemoryStream();
        var originalRequestBody = context.Request.Body;
        await originalRequestBody.CopyToAsync(requestBodyStream);
        requestBodyStream.Seek(0, SeekOrigin.Begin);
        var requestBodyText = await new StreamReader(requestBodyStream).ReadToEndAsync();
        context.Request.Body = originalRequestBody; // 将请求体重置为原始状态
        string? requestBody = requestBodyText;
        string? userName = "";

        if (requestBody.Contains("password"))
        {
            string pattern = @"(""password"":\s*"")(\w+)("")";
            string replacement = @"""password"":""*""";
            requestBody = Regex.Replace(requestBody, pattern, replacement);
        }

        if (requestBody.Contains("confirmPassword"))
        {
            string pattern = @"(""confirmPassword"":\s*"")(\w+)("")";
            string replacement = @"""confirmPassword"":""*""";
            requestBody = Regex.Replace(requestBody, pattern, replacement);
        }

        // 重置请求体
        requestBodyStream.Seek(0, SeekOrigin.Begin);
        context.Request.Body = requestBodyStream;

        // 处理请求
        using (var responseBodyStream = new MemoryStream())
        {
            var originalResponseBody = context.Response.Body;
            context.Response.Body = responseBodyStream;

            try
            {
                _timer.Start();
                await next(context);
                _timer.Stop();

                traceId = context.TraceIdentifier;
                Endpoint? endpoint = context.GetEndpoint();

                if (endpoint != null)
                {
                    // 获取终结点的元数据
                    var controllerActionDescriptor = endpoint.Metadata?.GetMetadata<ControllerActionDescriptor>();

                    // 获取控制器和动作的描述信息
                    controllerDescription = GetDescription(controllerActionDescriptor?.ControllerTypeInfo);
                    actionDescription = GetDescription(controllerActionDescriptor?.MethodInfo);

                    if (actionDescription == "密码登录")
                    {
                        string pattern = "\"username\"\\s*:\\s*\"([^\"]+)\"";
                        Match match = Regex.Match(requestBody, pattern);
                        if (match.Success)
                        {
                            userName = match.Groups[1].Value;
                        }
                        behavior = actionDescription;
                    }
                    else
                    {
                        userName = _currentUserService.UserName;
                    }
                }

                elapsedMilliseconds = _timer.ElapsedMilliseconds;
                responseBodyStream.Seek(0, SeekOrigin.Begin);
                var responseBodyText = await new StreamReader(responseBodyStream).ReadToEndAsync();
                // 记录响应头信息
                responseHeader = context?.Response?.Headers?.ToJson();
                responseBody = responseBodyText;
                responseBody = DecodeUnicodeSequences(responseBody);
                responseBodyStream.Seek(0, SeekOrigin.Begin);
                await responseBodyStream.CopyToAsync(originalResponseBody);
            }
            finally
            {
                int statusCode = context.Response.StatusCode;
                LogLevel logLevel;

                if (statusCode >= 200 && statusCode < 300 && elapsedMilliseconds < 500)
                {
                    logLevel = LogLevel.Information; // 成功的请求，记录为信息日志
                }
                else if (statusCode >= 400 && statusCode < 500)
                {
                    logLevel = LogLevel.Error; // 客户端错误，记录为错误日志
                }
                else if (statusCode >= 500 && statusCode < 600)
                {
                    logLevel = LogLevel.Critical; // 服务器错误，记录为失败日志
                }
                else
                {
                    logLevel = LogLevel.Warning; // 其他情况，可能记录为警告日志
                }
                if ((requestAPI.ToString().StartsWith("/api") && !requestAPI.ToString().Contains("/log/")))
                {
                    _logger.Log(logLevel, MessageTemplate.SystemLog, behavior, userName, id, controllerDescription, actionDescription, requestAPI, requestMethod, ip, location, os, browser, elapsedMilliseconds, requestTime, traceId, requestHeader, requestBody, responseHeader, responseBody, logLevel, statusCode);
                }

                context.Response.Body = originalResponseBody;
            }
        }
    }
    private string GetDescription(MemberInfo? memberInfo)
    {
        if (memberInfo == null) { return string.Empty; }
        var descriptionAttribute = memberInfo.GetCustomAttribute<DescriptionAttribute>();
        return descriptionAttribute != null ? descriptionAttribute.Description : string.Empty;
    }

    private string DecodeUnicodeSequences(string input)
    {
        if (string.IsNullOrWhiteSpace(input))
        {
            return input;
        }

        // 使用正则表达式匹配所有的Unicode转义序列
        string pattern = @"\\u([0-9a-fA-F]{4})";
        return Regex.Replace(input, pattern, m =>
        {
            // 将匹配的Unicode转义序列转换为实际的Unicode字符
            string hexValue = m.Groups[1].Value;
            int codePoint = Convert.ToInt32(hexValue, 16);
            byte[] utf8Bytes = new byte[sizeof(int)];
            utf8Bytes[0] = (byte)((codePoint & 0xFF0000) >> 16);
            utf8Bytes[1] = (byte)((codePoint & 0xFF00) >> 8);
            utf8Bytes[2] = (byte)(codePoint & 0xFF);
            return Encoding.UTF8.GetString(utf8Bytes);
        });
    }
}
